package generator

// hashTemplate Hash类型的模板
const hashTemplate = `package {{.Package}}

import (
	"fmt"

	"{{.ImportPath}}"
	"app/protos/out/cl"

	"gitee.com/lovengame/kit/sea/redis"
	"gitee.com/lovengame/kit/sea/util"

	"github.com/gogo/protobuf/proto"
	l4g "github.com/ivanabc/log4go"
)

const {{.Struct.DbStructName}}ProtoBufferSize = {{.BufferSize}}

func (client {{.Struct.ClientName}}) Get{{.Struct.Name}}() (*{{.Struct.PointStructName}}, error) {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}}

	params := make([]interface{}, 0, {{len .Struct.Fields}})
{{range .Struct.Fields}}
	params = append(params, "{{.Name}}")
{{end}}
	ptReply := client.Cmd("HMGET", strKeyName, params)
	return client.Get{{.Struct.Name}}ByReply(ptReply)
}

func (client {{.Struct.ClientName}}) Get{{.Struct.Name}}MCall() {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}}

	params := make([]interface{}, 0, {{len .Struct.Fields}})
{{range .Struct.Fields}}
	params = append(params, "{{.Name}}")
{{end}}
	client.Append("HMGET", strKeyName, params)
}

func (client {{.Struct.ClientName}}) Get{{.Struct.Name}}ByReply(
	ptReply *redis.Reply) (*{{.Struct.PointStructName}}, error) {

	bufs, err := ptReply.ListBytes()
	if err != nil {
		l4g.Errorf("RedisOp Get {{.Struct.Name}} Error %v", err)
		return nil, err
	}
	if len(bufs) == 0 {
		return nil, err
	}
	empty := true
	for _, buf := range bufs {
		if len(buf) > 0 {
			empty = false
			break
		}
	}
	if empty {
		return nil, err
	}

	data := &{{.Struct.PointStructName}}{}
{{range $index, $field := .Struct.Fields}}
	if len(bufs) > {{$index}} {
		buf := bufs[{{$index}}]
		if len(buf) > 0 {
{{if eq $field.Type "string"}}
			data.{{$field.HumpName}} = string(buf)
{{else if eq $field.Type "int64"}}
			neg := false
			if buf[0] == '-' {
				buf = buf[1:]
				neg = true
			}
			val, ok := util.ParseUint64(buf)
			if ok {
				var value int64
				if neg {
					value = -int64(val)
				} else {
					value = int64(val)
				}
				data.{{$field.HumpName}} = value
			} else {
				l4g.Errorf("parse int64 error %s", string(buf))
				return nil, fmt.Errorf("parse int64 error %s", string(buf))
			}
{{else if eq $field.Type "uint64"}}
			neg := false
			if buf[0] == '-' {
				buf = buf[1:]
				neg = true
			}
			val, ok := util.ParseUint64(buf)
			if ok {
				var value uint64
				if neg {
					value = -(val)
				} else {
					value = (val)
				}
				data.{{$field.HumpName}} = value
			} else {
				l4g.Errorf("parse int64 error %s", string(buf))
				return nil, fmt.Errorf("parse int64 error %s", string(buf))
			}
{{else}}
			if buf[0] != 0 {
				buf, err = UnCompressWithFlag(buf)
				if err != nil {
					l4g.Errorf("RedisOp UnCompress {{$.Struct.Name}}.{{$field.Name}} Unmarshal Error %v", err)
					return nil, err
				}
			} else {
				buf = buf[1:]
			}
			val := &{{$field.Type}}{}
			err = proto.Unmarshal(buf, val)
			if err != nil {
				l4g.Errorf("RedisOp Get {{$.Struct.Name}}.{{$field.Name}} Unmarshal Error %v", err)
				return nil, err
			}
			data.{{$field.HumpName}} = val
{{end}}
		}
	}
{{end}}
	return data, nil
}

func (client {{.Struct.ClientName}}) Set{{.Struct.Name}}(
	data *{{.Struct.PointStructName}}) error {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}}

	params := make([]interface{}, 0, {{len .Struct.Fields}}*2)

	{{range .Struct.Fields -}}
	{{if or (eq .Type "string") (eq .Type "uint64") (eq .Type "int64") -}}
	params = append(params, "{{.Name}}", data.Get{{.HumpName}}())

	{{else -}}
	if data.{{.HumpName}} != nil {
		buffer := proto.NewBuffer(make([]byte, 0, {{$.Struct.DbStructName}}ProtoBufferSize))
		bytes := buffer.Bytes()
		bytes = bytes[:1]
		bytes[0] = 0
		buffer.SetBuf(bytes)
		err := buffer.Marshal(data.{{.HumpName}})
		if err != nil {
			l4g.Errorf("RedisOp Marshal {{$.Struct.Name}}.{{.Name}} Error %v, Data: %+v", err, data)
		} else {
			buf := buffer.Bytes()
			if len(buf) > CompressBytes {
				buf, err = CompressWithFlag(buf, CompressFlagSnappy)
				if err != nil {
					l4g.Errorf("RedisOp Compress {{$.Struct.Name}}.{{.Name}} Error %v", err)
				}
			}
			params = append(params, "{{.Name}}", buf)
		}
	} else if data.{{.HumpName}}Op == db.Op_Delete {
		params = append(params, "{{.Name}}", "")
	}

	{{end -}}
	{{end -}}
	ptReply := client.Cmd("HMSET", strKeyName, params)
	if ptReply.Err != nil {
		l4g.Errorf("RedisOp Set {{.Struct.Name}} Error %v, Data: %+v", ptReply.Err, data)
		return ptReply.Err
	}
	return nil
}

func (client {{.Struct.ClientName}}) Set{{.Struct.Name}}MCall(
	data *{{.Struct.PointStructName}}) {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}}

	params := make([]interface{}, 0, {{len .Struct.Fields}}*2)

	{{range .Struct.Fields -}}
	{{if or (eq .Type "string") (eq .Type "uint64") (eq .Type "int64") -}}
	params = append(params, "{{.Name}}", data.Get{{.HumpName}}())

	{{else -}}
	if data.{{.HumpName}} != nil {
		buffer := proto.NewBuffer(make([]byte, 0, {{$.Struct.DbStructName}}ProtoBufferSize))
		bytes := buffer.Bytes()
		bytes = bytes[:1]
		bytes[0] = 0
		buffer.SetBuf(bytes)
		err := buffer.Marshal(data.{{.HumpName}})
		if err != nil {
			l4g.Errorf("RedisOp Marshal {{$.Struct.Name}}.{{.Name}} Error %v, Data: %+v", err, data)
		} else {
			buf := buffer.Bytes()
			if len(buf) > CompressBytes {
				buf, err = CompressWithFlag(buf, CompressFlagSnappy)
				if err != nil {
					l4g.Errorf("RedisOp Compress {{$.Struct.Name}}.{{.Name}} Error %v", err)
				}
			}
			params = append(params, "{{.Name}}", buf)
		}
	} else if data.{{.HumpName}}Op == db.Op_Delete {
		params = append(params, "{{.Name}}", "")
	}

	{{end -}}
	{{end -}}
	client.Append("HMSET", strKeyName, params)
}

func (client {{.Struct.ClientName}}) Del{{.Struct.Name}}() error {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}}
	ptReply := client.Cmd("DEL", strKeyName)
	if ptReply.Err != nil {
		l4g.Errorf("RedisOp Del {{.Struct.Name}} Error %v", ptReply.Err)
		return ptReply.Err
	}
	return nil
}

func (client {{.Struct.ClientName}}) Del{{.Struct.Name}}MCall() {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}}
	client.Append("DEL", strKeyName)
}
`

// hashTemplate Hash类型的模板
const hashTemplateWithSuffix = `package {{.Package}}

import (
	"fmt"
	"strconv"

	"{{.ImportPath}}"

	"gitee.com/lovengame/kit/sea/redis"
	"gitee.com/lovengame/kit/sea/util"

	"github.com/gogo/protobuf/proto"
	l4g "github.com/ivanabc/log4go"
)

const {{.Struct.DbStructName}}ProtoBufferSize = {{.BufferSize}}

func (client {{.Struct.ClientName}}) Get{{.Struct.Name}}SK(
	sufKey {{.Struct.KeyType}}) (*{{.Struct.PointStructName}}, error) {

	return client.Get{{.Struct.Name}}SKs(strconv.FormatUint(sufKey, 10))
}

func (client {{.Struct.ClientName}}) Get{{.Struct.Name}}MCallSK(
	sufKey {{.Struct.KeyType}}) {

	client.Get{{.Struct.Name}}MCallSKs(strconv.FormatUint(sufKey, 10))
}

func (client {{.Struct.ClientName}}) Set{{.Struct.Name}}SK(
	sufKey {{.Struct.KeyType}}, data *{{.Struct.PointStructName}}) error {

	return client.Set{{.Struct.Name}}SKs(strconv.FormatUint(sufKey, 10), data)
}

func (client {{.Struct.ClientName}}) Set{{.Struct.Name}}MCallSK(
	sufKey {{.Struct.KeyType}}, data *{{.Struct.PointStructName}}) {

	client.Set{{.Struct.Name}}MCallSKs(strconv.FormatUint(sufKey, 10), data)
}

func (client {{.Struct.ClientName}}) Del{{.Struct.Name}}SK(
	sufKey {{.Struct.KeyType}}) error {

	return client.Del{{.Struct.Name}}SKs(strconv.FormatUint(sufKey, 10))
}

func (client {{.Struct.ClientName}}) Del{{.Struct.Name}}MCallSK(
	sufKey {{.Struct.KeyType}}) {

	client.Del{{.Struct.Name}}MCallSKs(strconv.FormatUint(sufKey, 10))
}

//=========================以下是具体实现=========================

func (client {{.Struct.ClientName}}) Get{{.Struct.Name}}SKs(
	sufKey string) (*{{.Struct.PointStructName}}, error) {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}} + sufKey

	params := make([]interface{}, 0, {{len .Struct.Fields}})

	{{range .Struct.Fields -}}
	params = append(params, "{{.Name}}")

	{{end -}}
	ptReply := client.Cmd("HMGET", strKeyName, params)
	return client.Get{{.Struct.Name}}ByReply(ptReply)
}

func (client {{.Struct.ClientName}}) Get{{.Struct.Name}}MCallSKs(
	sufKey string) {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}} + sufKey

	params := make([]interface{}, 0, {{len .Struct.Fields}})

	{{range .Struct.Fields -}}
	params = append(params, "{{.Name}}")

	{{end -}}
	client.Append("HMGET", strKeyName, params)
}

func (client {{.Struct.ClientName}}) Get{{.Struct.Name}}ByReply(
	ptReply *redis.Reply) (*{{.Struct.PointStructName}}, error) {

	bufs, err := ptReply.ListBytes()
	if err != nil {
		l4g.Errorf("RedisOp Get {{.Struct.Name}} Error %v", err)
		return nil, err
	}
	if len(bufs) == 0 {
		return nil, err
	}
	empty := true
	for _, buf := range bufs {
		if len(buf) > 0 {
			empty = false
			break
		}
	}
	if empty {
		return nil, err
	}

	data := &{{.Struct.PointStructName}}{}

	{{range $index, $field := .Struct.Fields -}}

	if len(bufs) > {{$index}} {
		buf := bufs[{{$index}}]
		if len(buf) > 0 {

			{{if eq $field.Type "string" -}}
			data.{{$field.HumpName}} = string(buf)

		{{else if eq $field.Type "int64" -}}
			neg := false
			if buf[0] == '-' {
				buf = buf[1:]
				neg = true
			}
			val, ok := util.ParseUint64(buf)
			if ok {
				var value int64
				if neg {
					value = -int64(val)
				} else {
					value = int64(val)
				}
				data.{{$field.HumpName}} = value
			} else {
				l4g.Errorf("parse int64 error %s", string(buf))
				return nil, fmt.Errorf("parse int64 error %s", string(buf))
			}

		{{else if eq $field.Type "uint64" -}}
			neg := false
			if buf[0] == '-' {
				buf = buf[1:]
				neg = true
			}
			val, ok := util.ParseUint64(buf)
			if ok {
				var value uint64
				if neg {
					value = -(val)
				} else {
					value = (val)
				}
				data.{{$field.HumpName}} = value
			} else {
				l4g.Errorf("parse int64 error %s", string(buf))
				return nil, fmt.Errorf("parse int64 error %s", string(buf))
			}

		{{else -}}
			if buf[0] != 0 {
				buf, err = UnCompressWithFlag(buf)
				if err != nil {
					l4g.Errorf("RedisOp UnCompress {{$.Struct.Name}}.{{$field.Name}} Unmarshal Error %v", err)
					return nil, err
				}
			} else {
				buf = buf[1:]
			}
			val := &{{$field.Type}}{}
			err = proto.Unmarshal(buf, val)
			if err != nil {
				l4g.Errorf("RedisOp Get {{$.Struct.Name}}.{{$field.Name}} Unmarshal Error %v", err)
				return nil, err
			}
			data.{{$field.HumpName}} = val

		{{end -}}
		}
	}

	{{end -}}

	return data, nil
}

func (client {{.Struct.ClientName}}) Set{{.Struct.Name}}SKs(
	sufKey string, data *{{.Struct.PointStructName}}) error {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}} + sufKey

	params := make([]interface{}, 0, {{len .Struct.Fields}}*2)

	{{range .Struct.Fields -}}
	{{if or (eq .Type "string") (eq .Type "uint64") (eq .Type "int64") -}}
	params = append(params, "{{.Name}}", data.Get{{.HumpName}}())

	{{else -}}
	if data.{{.HumpName}} != nil {
		buffer := proto.NewBuffer(make([]byte, 0, {{$.Struct.DbStructName}}ProtoBufferSize))
		bytes := buffer.Bytes()
		bytes = bytes[:1]
		bytes[0] = 0
		buffer.SetBuf(bytes)
		err := buffer.Marshal(data.{{.HumpName}})
		if err != nil {
			l4g.Errorf("RedisOp Marshal {{$.Struct.Name}}.{{.Name}} Error %v, Data: %+v", err, data)
		} else {
			buf := buffer.Bytes()
			if len(buf) > CompressBytes {
				buf, err = CompressWithFlag(buf, CompressFlagSnappy)
				if err != nil {
					l4g.Errorf("RedisOp Compress {{$.Struct.Name}}.{{.Name}} Error %v", err)
				}
			}
			params = append(params, "{{.Name}}", buf)
		}
	} else if data.{{.HumpName}}Op == db.Op_Delete {
		params = append(params, "{{.Name}}", "")
	}

	{{end -}}
	{{end -}}

	ptReply := client.Cmd("HMSET", strKeyName, params)
	if ptReply.Err != nil {
		l4g.Errorf("RedisOp Set {{.Struct.Name}} Error %v, Data: %+v", ptReply.Err, data)
		return ptReply.Err
	}
	return nil
}

func (client {{.Struct.ClientName}}) Set{{.Struct.Name}}MCallSKs(
	sufKey string, data *{{.Struct.PointStructName}}) {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}} + sufKey

	params := make([]interface{}, 0, {{len .Struct.Fields}}*2)

	{{range .Struct.Fields -}}
	{{if or (eq .Type "string") (eq .Type "uint64") (eq .Type "int64") -}}
	params = append(params, "{{.Name}}", data.Get{{.HumpName}}())

	{{else -}}
	if data.{{.HumpName}} != nil {
		buffer := proto.NewBuffer(make([]byte, 0, {{$.Struct.DbStructName}}ProtoBufferSize))
		bytes := buffer.Bytes()
		bytes = bytes[:1]
		bytes[0] = 0
		buffer.SetBuf(bytes)
		err := buffer.Marshal(data.{{.HumpName}})
		if err != nil {
			l4g.Errorf("RedisOp Marshal {{$.Struct.Name}}.{{.Name}} Error %v, Data: %+v", err, data)
		} else {
			buf := buffer.Bytes()
			if len(buf) > CompressBytes {
				buf, err = CompressWithFlag(buf, CompressFlagSnappy)
				if err != nil {
					l4g.Errorf("RedisOp Compress {{$.Struct.Name}}.{{.Name}} Error %v", err)
				}
			}
			params = append(params, "{{.Name}}", buf)
		}
	} else if data.{{.HumpName}}Op == db.Op_Delete {
		params = append(params, "{{.Name}}", "")
	}

	{{end -}}
	{{end -}}
	client.Append("HMSET", strKeyName, params)
}

func (client {{.Struct.ClientName}}) Del{{.Struct.Name}}SKs(
	sufKey string) error {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}} + sufKey
	ptReply := client.Cmd("DEL", strKeyName)
	if ptReply.Err != nil {
		l4g.Errorf("RedisOp Del {{.Struct.Name}} Error %v", ptReply.Err)
		return ptReply.Err
	}
	return nil
}

func (client {{.Struct.ClientName}}) Del{{.Struct.Name}}MCallSKs(
	sufKey string) {

	strKeyName := RedisOpKeyHash{{.Struct.DbStructName}} + sufKey
	client.Append("DEL", strKeyName)
}
`
